#include"socket.hpp"

#include<vector>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include<unordered_map>

std::string defaultip = "0.0.0.0";
int16_t defaultport = 8090;

std::string interval = "\r\n";

std::string wwwroot = "./wwwroot";

std::string homepage = "index.html";

struct HttpRequest
{
    void Deserialization(std::string buf)
    {
        while(1)
        {
            size_t pos = buf.find(interval);
            _arr.push_back(buf.substr(0, pos));
            buf.erase(0, pos);
            if(pos = std::string::npos) break;
        }
    }

    void debugger_print()
    {
        std::cout << "debug" << std::endl;
        // for(auto& e : _arr)
        // {
        //     std::cout << e << std::endl;
        // }
        std::cout << _method << std::endl;
        std::cout << _url << std::endl;
        std::cout << _path << std::endl;
    }

    void parse()
    {
        size_t left = _arr[0].find(" ");
        _method = _arr[0].substr(0, left);
        size_t right = _arr[0].find(" ", left + 1);
        _url = _arr[0].substr(left + 1, right - left - 1);

        _path = wwwroot;
        if(_url == "/" || _url == "/index.html")
        {
            _path += "/";
            _path += homepage;
        }
        else _path += _url;

        size_t pos = _path.rfind(".");
        if(pos != std::string::npos) _type = _path.substr(pos + 1);
        else _type = "html";
    }

    std::vector<std::string> _arr;
    std::string _method;
    std::string _url;
    // std::string _httpversion;
    std::string _path;
    std::string _type;
};

class httpserver
{
public:
    httpserver(const std::string& ip = defaultip, int16_t port = defaultport):
        _ip(ip),
        _port(port)
    {
        _mp["html"] = "text/html";
        _mp["png"] = "image/png";
    }

    void init()
    {
        _sk.my_socket();
        _sk.my_bind(_ip, _port);
        _sk.my_listen();
    }

    long get_file_size(FILE *stream)
    {
        long file_size = -1;
        long cur_offset = ftell(stream);	// 获取当前偏移位置
        if (cur_offset == -1) 
        {
            printf("ftell failed :%s\n", strerror(errno));
            return -1;
        }
        if (fseek(stream, 0, SEEK_END) != 0) 
        {	// 移动文件指针到文件末尾
            printf("fseek failed: %s\n", strerror(errno));
            return -1;
        }
        file_size = ftell(stream);	// 获取此时偏移值，即文件大小
        if (file_size == -1) 
        {
            printf("ftell failed :%s\n", strerror(errno));
        }
        if (fseek(stream, cur_offset, SEEK_SET) != 0) 
        {	// 将文件指针恢复初始位置
            printf("fseek failed: %s\n", strerror(errno));
            return -1;
        }
        return file_size;
    }

    void HandlerHttp(int sockfd)
    {
        char buffer[1024] = {0};
        while(1)
        {   
            _sk.my_close();
            ssize_t n = read(sockfd, buffer, sizeof(buffer));
            if(n > 0)
            {
                buffer[n] = 0;
                std::cout << buffer << std::endl;

                // std::string text = "<h1>hello world</h1>";

                HttpRequest _hr;
                _hr.Deserialization(buffer);
                _hr.parse();
                // _hr.debugger_print();

                // char rebuf[10240] = {0};
                // int fd = open(_hr._path.c_str(), O_RDONLY);
                // if(fd < 0) fd = open("./wwwroot/err.html", O_RDONLY);
                // read(fd, rebuf, 10240);
                // std::cout << rebuf << std::endl;

                FILE* fp = fopen(_hr._path.c_str(), "rb");
                long file_size = get_file_size(fp);

                std::string text;
                text.resize(file_size);
                fread((void*)text.c_str(), 1, file_size, fp);

                // std::cout << file_size << std::endl;
                // std::cout << text << std::endl;
                fclose(fp);
                std::string message = "HTTP/1.1 200 OK\r\n";
                message += "Content-Length: ";
                message += std::to_string(file_size);
                message += interval;
                // message += "Location: https://www.bilibili.com";

                message += "Content-Type: ";
                message += _mp[_hr._type];
                message += interval;

                // message += "Location: https://www.bilibili.com";
                // message += interval;

                message += "Set-Cookie: username=thx";
                message += interval;
                message += "Set-Cookie: password=123456";
                message += interval;

                message += "\r\n";
                message += text;
                // std::cout << message << std::endl;
                write(sockfd, message.c_str(), message.size());
                // std::cout << message << std::endl;

                // _hr.debugger_print();
            }
            else break;
        }
        exit(0);
    }

    void start()
    {
        while(1)
        {
            std::string clientip;
            int16_t clientport;
            int sockfd = _sk.my_accept(clientip, clientport);
            std::cout << "get a new connect" << std::endl;
            if(fork() == 0)
            {
                HandlerHttp(sockfd);
            }
            close(sockfd);
        }
    }

    ~httpserver()
    {
        _sk.my_close();
    }
private:
    sock _sk;
    std::string _ip;
    int16_t _port;
    std::unordered_map<std::string, std::string> _mp;
};